/* License Notice:
**
** This program is free software: you can redistribute it and/or modify
**    it under the terms of the GNU General Public License as published by
**    the Free Software Foundation, either version 3 of the License, or
**    (at your option) any later version.
** This program is distributed in the hope that it will be useful,
**   but WITHOUT ANY WARRANTY; without even the implied warranty of
**   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
**   GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
**   along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
 * @file fifo_simple.hpp
 * @author TooOld2Rock'nRoll
 * @date ago/2005
 * @version 4.0.0
 *
 * @remark Statistics are just reference values and you should use the
 *           fifo_runBenchmarkTest() function to get specific values for your project.
 * @attention "make CFLAGS:=-DUNIT_TESTING" to run unit testing on the library.
 *
 * @see Cormen, Thomas H. (...) - Introduction to Algorithms (2ºed)
 * @see Deitel, H. M. (...) - How to Program C++ (3ªed)
 * @see https://cpputest.github.io/manual.html
 *
 * @brief Header file for the <i>simple</i> version for FIFO (First In / First Out) data structure.
 */
#ifndef FIFO_S_HPP
#define FIFO_S_HPP

/*---- Includes ----*/
#include <cstddef>

#ifdef UNIT_TESTING
#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTest/MemoryLeakDetectorNewMacros.h>
#endif


/*---- Class Declaration ----*/
/**
 * @brief Simples (true) FIFO data structure.
 * @see https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)
 *
 * A FIFO a queue of nodes that are accessed sequentially from head to tail.<br>
 *
 * This is a <i>simples</i> (or true) queue in the sense that it can only push new nodes to the tail and pop from the head!
 *
 * It is, however, thread compliant! It is not guaranteed to be consistent under any condition, it wouldn't be hard to
 *   implement thread safeguards at this level for a true queue, but it would be useless and extra processing for single
 *   thread programs.<br>
 * So remember to add your own if required!<br>
 *
 * The push() function adds a new node to the queue tail.<br>
 * The pop() function takes out a queue's node at the head.<br>
 * The read() function peeks at the queue head, but does not remove the node.<br>
 * The other functions are just helpers that make some jobs easier.<br>
 * A report will be printed on destruct if ENABLE_BENCHMARK flag is active.<br>
 *
 * Example:
 * <code>
 *   int buff = 0;
 *   FIFO<int> TheQueue;
 *
 *   TheQueue.push (10);
 *
 *   TheQueue.push (20);
 *
 *   //remove the queue head node (the first inserted)
 *   TheQueue.pop (&buff);
 *   //buff == 10
 *
 *   //20 remains and will be dealt with in the destructor.
 *
 *   //a report may be printed
 * </code>
 *
 *  -Statistics for T<unsigned>:<br>
 *   Total Used Time: 0.0130s
 *      Push
 *        -was called 50000 times.
 *        -total used time: 0.007000s
 *        -Average Delay: 0.000140ms
 *      Pop
 *        -was called 50000 times.
 *        -total used time: 0.006000s
 *        -Average Delay: 0.000120ms
 *  -Machine Specs:<br>
 *     Intel Core i7-7700HQ CPU @ 2.80GHz<br>
 *     16Gb RAM<br>
 *
 * @tparam T - data type to be stored in the queue.
 */
template <typename T>
class FIFO
{
    private:
        //the node structure that builds the queue
        struct node_s
        {
            T _package; //user data
            node_s *_next = nullptr; //pointer to next node or null if last one
        };//end node_s

        std::size_t _size = 0;//the number of nodes in the queue

        node_s *_head = nullptr; //first node of the queue or null if empty
        node_s *_tail = nullptr; //last node of the queue or null if empty


    protected:


    public:
        FIFO ();
        ~FIFO ();

        void push (const T &package);
        T* pop (T &buffer);
        const T* head () const;

        void clean ();

        /** @brief Returns <b>true</b> if queue is empty, <b>false</b> otherwise. */
        bool empty () const { return (this->_size == 0); }
        /** @brief Returns the number of nodes stored in the queue. */
        std::size_t size () const { return this->_size; }
};//END FIFO

#endif //FIFO_S_HPP

